package com.tbit.uqbike.service.business.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.PatternPool;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.page.PageMethod;
import com.sun.mail.smtp.SMTPAddressFailedException;
import com.tbit.common.config.OssDefaultConfig;
import com.tbit.common.constant.CommonConstant;
import com.tbit.uqbike.constant.Constants;
import com.tbit.uqbike.constant.InvoiceRecordConstant;
import com.tbit.uqbike.constant.OperaPswConstant;
import com.tbit.uqbike.manager.exception.BaseException;
import com.tbit.uqbike.object.pojo.*;
import com.tbit.uqbike.object.pojo.vo.InvoiceOrderDetailVO;
import com.tbit.uqbike.object.pojo.vo.InvoiceRecordVO;
import com.tbit.common.entity.view.PageResult;
import com.tbit.common.entity.view.Result;
import com.tbit.uqbike.service.business.InvoiceRecordService;
import com.tbit.uqbike.webmanager.dao.core.*;
import com.tbit.uqbike.webmanager.sms.ApiStoreMsgUtils;
import com.tbit.uqbike.webmanager.util.aliyun.OssFileUtils;
import com.tbit.utils.DateTimeUtil;
import com.tbit.utils.NullUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.MailSendException;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author yee_
 * @version 1.0
 * @date 2023/8/8 14:34
 */
@Slf4j
@Service
public class InvoiceRecordServiceImpl extends ServiceImpl<InvoiceRecordDao, InvoiceRecord> implements InvoiceRecordService {
    private static final String RECORD_NOT_FIND_MESSAGE = "编号[%s]申请记录不存在。";
    @Resource
    private InvoiceRecordDao invoiceRecordDao;
    @Resource
    private JavaMailSender mailSender;
    @Resource
    private OssConfigDao ossConfigDao;
    @Resource
    private OssDefaultConfig ossDefaultConfig;
    @Resource
    private AccountDao accountDao;
    @Resource
    private UsermsgDao usermsgDao;
    @Resource
    private SmsAuthConfigDao smsAuthConfigDao;
    @Value("${spring.mail.username:}")
    private String mailUserName;

    @Override
    public PageResult<InvoiceRecord> listPage(String phone, String email, Integer status, Long startTime, Long endTime,
                                              Integer brandId, String flowId, Integer page, Integer size) {
        PageInfo<InvoiceRecord> pageInfo = PageMethod.startPage(page, size).doSelectPageInfo(() -> {
            LambdaQueryWrapper<InvoiceRecord> queryWrapper = new LambdaQueryWrapper<>();
            if (StringUtils.isNotBlank(phone)) {
                queryWrapper.eq(InvoiceRecord::getUserPhone, phone);
            }
            if (Objects.nonNull(status)) {
                queryWrapper.eq(InvoiceRecord::getStatus, status);
            }
            if (StringUtils.isNotBlank(flowId)) {
                queryWrapper.eq(InvoiceRecord::getFlowId, flowId);
            }
            if (StringUtils.isNotBlank(email)) {
                queryWrapper.like(InvoiceRecord::getEmail, email);
            }
            if (Objects.nonNull(startTime) && Objects.nonNull(endTime)) {
                queryWrapper.ge(InvoiceRecord::getApplyTime, new Date(startTime));
                queryWrapper.le(InvoiceRecord::getApplyTime, new Date(endTime));
            }
            queryWrapper.eq(InvoiceRecord::getBrandId, brandId);
            queryWrapper.notIn(InvoiceRecord::getStatus, InvoiceRecordConstant.STATUS_REOPEN_NEW);
            queryWrapper.orderBy(true, false, InvoiceRecord::getId);
            invoiceRecordDao.selectList(queryWrapper);
        });
        return new PageResult<>(page, size, pageInfo.getTotal(), pageInfo.getPages(), pageInfo.getList());
    }

    @Override
    public Result<InvoiceRecordVO> detail(Integer invoiceId) {
        InvoiceRecord invoiceRecord = invoiceRecordDao.selectById(invoiceId);
        if (Objects.isNull(invoiceRecord)) {
            return Result.error(String.format(RECORD_NOT_FIND_MESSAGE, invoiceId));
        }
        List<InvoiceOrderDetailVO> rideLogList = invoiceRecordDao.selectOrderInfoByTypeAndInvoiceId(invoiceId, invoiceRecord.getOrderType());
        return Result.success(new InvoiceRecordVO(invoiceRecord, rideLogList));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<String> audit(Integer invoiceId, Boolean auditStatus, String invoiceNumber, MultipartFile file, String remark) {
        InvoiceRecord invoiceRecord = invoiceRecordDao.selectById(invoiceId);
        if (Objects.isNull(invoiceRecord)) {
            return Result.error(String.format(RECORD_NOT_FIND_MESSAGE, invoiceId));
        }
        if (invoiceRecord.audited()) {
            return Result.error(String.format("编号[%s]申请记录已处理,请勿重复操作。", invoiceId));
        }
        if (invoiceRecord.reopenReview()) {
            return Result.error(String.format("编号[%s]状态有误,请勿操作。", invoiceId));
        }
        Integer brandId = invoiceRecord.getBrandId();
        if (auditStatus) {
            if (!PatternPool.EMAIL.matcher(invoiceRecord.getEmail()).matches()) {
                return Result.error("邮箱地址不正确,请修改新邮箱地址后重新审核");
            }
            //发票上传到阿里云
            OssConfig ossConfig = Optional.ofNullable(ossConfigDao.getByAccountId(brandId))
                    .orElseGet(() -> new OssConfig(ossDefaultConfig.getEndpoint(),
                            ossDefaultConfig.getAccessKeyId(),
                            ossDefaultConfig.getAccessKeySecret(), "gx-res"));
            //No suitable ImageReader found for source data.
            //阿里云oss上传pdf文件失败
            String fileUrl = OssFileUtils.upload(file, ossConfig);
            invoiceRecord.setUrl(fileUrl);
            invoiceRecord.setInvoiceNumber(invoiceNumber);
        }
        int updateState = auditStatus ? InvoiceRecordConstant.STATUS_SUCCESS : InvoiceRecordConstant.STATUS_REJECT;
        invoiceRecord.setStatus(updateState);
        invoiceRecord.setInvoiceTime(new Date());
        invoiceRecord.setRemark(remark);
        //修改主记录
        invoiceRecordDao.updateById(invoiceRecord);
        //修改订单关联记录
        invoiceRecordDao.updateInvoiceOrderBound(invoiceId, updateState, InvoiceRecordConstant.STATUS_APPLY);

        if (auditStatus) {
            String brandName = Optional.ofNullable(accountDao.getByAccountId(brandId))
                    .map(Account::getName)
                    .orElse("");
            String title = String.format("%s电子发票", brandName);
            try {
                MimeMessageHelper messageHelper = new MimeMessageHelper(mailSender.createMimeMessage(), true);
                messageHelper.setFrom(mailUserName);
                messageHelper.setTo(invoiceRecord.getEmail());
                messageHelper.setSubject(title);
                messageHelper.setText("");
                messageHelper.addAttachment(title + ".pdf", file);
                messageHelper.setSentDate(new Date());
                mailSender.send(messageHelper.getMimeMessage());
            } catch (SMTPAddressFailedException e) {
                log.error("电子发票邮件投递失败", e);
                throw new BaseException("邮件投递失败,失败原因:" + e.getMessage());
            }catch (MailSendException e){
                log.error("电子邮件发送失败，邮件地址错误");
                throw new BaseException("邮件发送失败,邮箱地址错误");
            }catch (Exception e) {
                log.error("电子发票邮件发送失败", e);
                throw new BaseException("电子发票邮件发送失败");
            }
        }
        String dateSimple = DateUtil.format(new Date(), "yyyy年MM月dd日");
        String smsMessage = auditStatus ? "尊敬的用户：您于%s申请的增值税电子普通发票已发至您的邮箱，请您注意查收。如您没有收到邮件，请在“开票历史”页面查看开票记录，并点击“重发发票”。" :
                "尊敬的用户：您于%s申请的电子发票开票审核未通过，详情请登录小程序查看。";
        remark = StringUtils.isBlank(remark) ? "" : "原因：" + remark;
        String noticeMessage = auditStatus ? smsMessage : "尊敬的用户：您于%s申请的电子发票开票审核未通过。" + remark;
        sendMessage(String.format(smsMessage, dateSimple), brandId, invoiceRecord.getUserPhone());
        usermsgDao.insertSelective(new Usermsg(invoiceRecord.getUserId(), "发票审核结果通知", String.format(noticeMessage, dateSimple)));
        return Result.success("处理成功");
    }


    private void sendMessage(String message, Integer brandId, String userPhone) {
        Account brandArea = accountDao.getByAccountId(brandId);
        SmsAuthConfig smsAuthConfig = smsAuthConfigDao.selectSmsConfigAndType(brandId, 14);
        if (!NullUtils.isEmpty(smsAuthConfig)) {
            //寻程发送短信*/
            ApiStoreMsgUtils.sendModelSms(userPhone, smsAuthConfig.getSmsCodeKey(),
                    Integer.valueOf(smsAuthConfig.getModelId()), brandArea.getName(),
                    message
            );
        }
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public Result<String> discard(Integer invoiceId, Boolean auditStatus) {
        InvoiceRecord invoiceRecord = invoiceRecordDao.selectById(invoiceId);
        if (Objects.isNull(invoiceRecord)) {
            return Result.error(String.format(RECORD_NOT_FIND_MESSAGE, invoiceId));
        }
        if (!invoiceRecord.waitReview()) {
            return Result.error(String.format("编号[%s]记录状态不是重开待审核,处理失败。", invoiceId));
        }
        Integer newId = invoiceRecord.getNewId();
        if (auditStatus) {
            invoiceRecordDao.updateInvoiceOrderBound(invoiceId, InvoiceRecordConstant.STATUS_ABANDON, InvoiceRecordConstant.STATUS_REOPEN);
            invoiceRecord.setRefundTime(new Date());
            //如果是用户主动废弃重开,修改新发票记录状态
            if (Objects.nonNull(newId)) {
                invoiceRecordDao.updateStatusById(newId, InvoiceRecordConstant.STATUS_APPLY, InvoiceRecordConstant.STATUS_REOPEN_NEW);
                invoiceRecordDao.updateInvoiceOrderBound(newId, InvoiceRecordConstant.STATUS_APPLY, InvoiceRecordConstant.STATUS_REOPEN_NEW);
            }
            //自动开票---确认红冲，以及自动开票
//            this.dealRedChong(invoiceRecord,InvoiceRecordConstant.RED_CHONG_CONFIRM);
        } else {
            if (Objects.nonNull(newId)) {
                invoiceRecord.setNewId(null);
                invoiceRecordDao.deleteById(newId);
                invoiceRecordDao.deleteInvoiceOrderBoundByInvoiceId(newId);
                //自动开票拒绝红冲
//                this.dealRedChong(invoiceRecord,InvoiceRecordConstant.RED_CHONG_REFUSE);
            }
        }
        Integer beforeStatus = Objects.isNull(invoiceRecord.getUrl()) ? InvoiceRecordConstant.STATUS_APPLY : InvoiceRecordConstant.STATUS_SUCCESS;
        invoiceRecord.setStatus(auditStatus ? InvoiceRecordConstant.STATUS_ABANDON : beforeStatus);
        invoiceRecordDao.updateById(invoiceRecord);
        String dateSimple = DateUtil.format(new Date(), "yyyy年MM月dd日");
        String smsMessage = auditStatus ? "尊敬的用户:您于%s提交的电子发票重开申请已通过，新的发票开具成功后会发送到您的邮箱。" :
                "尊敬的用户:您于%s提交的电子发票重开申请审核未通过，详情请登录小程序查看。";
        String noticeMessage = auditStatus ? smsMessage : "尊敬的用户:您于%s提交的电子发票重开申请审核未通过。";
        sendMessage(String.format(smsMessage, dateSimple), invoiceRecord.getBrandId(), invoiceRecord.getUserPhone());
        usermsgDao.insertSelective(new Usermsg(invoiceRecord.getUserId(), "发票审核结果通知", String.format(noticeMessage, dateSimple)));
        return Result.success();
    }

    @Override
    public Result<String> updateEmail(Integer invoiceId, String email) {
        InvoiceRecord invoiceRecord = invoiceRecordDao.selectById(invoiceId);
        if (Objects.isNull(invoiceRecord)) {
            return Result.error(String.format(RECORD_NOT_FIND_MESSAGE, invoiceId));
        }
        if (invoiceRecord.getStatus() == 1) {
            return Result.error(String.format("编号[%s]已开票。请勿修改邮箱", invoiceId));
        }
        invoiceRecord.setEmail(email);
        invoiceRecordDao.updateById(invoiceRecord);
        return Result.success();
    }

    @Override
    public Result<Boolean> queryOrderHasBeenInvoicedByOrderNo(String orderNo) {
        Boolean invoiced = invoiceRecordDao.queryOrderHasBeenInvoicedByOrderNo(orderNo);
        return Result.success(invoiced);
    }

    @Override
    public List<InvoiceRecord> selectList(Integer userId, Integer brandId, Date startTime, Date endTime) {
        QueryWrapper<InvoiceRecord> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(InvoiceRecord::getUserId, userId)
                .eq(InvoiceRecord::getBrandId, brandId)
                .ge(Objects.nonNull(startTime), InvoiceRecord::getApplyTime, startTime)
                .le(Objects.nonNull(endTime), InvoiceRecord::getApplyTime, endTime);
        return invoiceRecordDao.selectList(wrapper);
    }

    /**
     * @description: 重新自动开票
     * @author: mo.shanyong
     * @date: 2025/4/7 11:49
     * @param: invoiceRecord 旧发票
     */
    @Override
    public void reAutoInvoicing(Integer invoiceId){
        InvoiceRecord invoiceRecord = invoiceRecordDao.selectById(invoiceId);
        //如果是手动开票则直接返回
        if (Objects.equals(invoiceRecord.getInvoiceOpenType(),InvoiceRecordConstant.INVOICE_OPEN_TYPE_HAND_INVOICE)
        || (Objects.equals(invoiceRecord.getStatus(),InvoiceRecordConstant.STATUS_REOPEN) && StringUtils.isBlank(invoiceRecord.getInvoiceNumber()))){
            return;
        }
        String url = OperaPswConstant.ACCOUNT_OPERA_CLIENT_URL + InvoiceRecordConstant.RE_AUTO_INVOICING_URI;
        Map<String, Object> map = new HashMap<>();
        map.put("invoiceId",invoiceRecord.getId());
        try {
            String body = HttpRequest.post(url).form(map).execute().body();
            JSONObject jsonObject = JSON.parseObject(body);
            log.info("调用客户端重新自动开票接口,请求参数={},客户端返回{}", JSON.toJSONString(map), JSON.toJSONString(jsonObject));
            if (!Objects.equals(jsonObject.get("ret").toString(),"1")) {
                throw new BaseException(jsonObject.get("msg").toString());
            }
        }catch (Exception e){
            log.info("调用客户端重新自动开票接口错误，e",e);
            throw new BaseException(e.getMessage());
        }
    }
}
